import json
import time
import random

import xlrd
import redis
import requests
from flask import Flask,request
from flask_cors import CORS

import color_convert


class my_color:
    def __init__(self, color_desc, color_class, l, a, b, R, G, B):
        self.color_desc = color_desc
        self.color_class = color_class
        self.color_l = l
        self.color_a = a
        self.color_b = b
        self.color_R = R
        self.color_G = G
        self.color_B = B
        self.lab = ((l << 16) | (a << 8) | b)
        self.rgb = ((R << 16) | (G << 8) | B)

    def __repr__(self) -> str:
        return (
            "color_item:  color_desc: {}, color_class: {}, color_l: {}, color_a: {}, color_b: {}, color_R: {}, color_G: {}, color_B: {}, lab: {}, rgb: {}"
            .format(
                self.color_desc,
                self.color_class,
                self.color_l,
                self.color_a,
                self.color_b,
                self.color_R,
                self.color_G,
                self.color_B,
                self.lab,
                self.rgb,
            ))


# flask
app = Flask(__name__)
CORS(app, supports_credentials=True)

# redis connect
redis_conn = redis.Redis(host='127.0.0.1', port=6379)

# color_config table
all_color_config = {}
background_config = {}
all_color_list = []
all_color_list_back = []
background_list = []

# 初始化模式标题字体颜色
# title_front_color_list[0] = "#ffffff" # 纯白
# title_front_color_list[1] = "#000000" # 纯黑
title_front_color_list = ["#ffffff", "#000000"] # 程序定义


# 解析所有颜色 分类存
def parse_color_table(excel_all_color_sheet):
    all_class_color = {}
    nrow = excel_all_color_sheet.nrows
    for i in range(nrow):
        if i < 2:
            continue
        color_desc = excel_all_color_sheet.cell_value(i, 0)
        color_class = int(excel_all_color_sheet.cell_value(i, 1))
        color_l = int(excel_all_color_sheet.cell_value(i, 2))
        color_a = int(excel_all_color_sheet.cell_value(i, 3))
        color_b = int(excel_all_color_sheet.cell_value(i, 4))
        color_R = int(excel_all_color_sheet.cell_value(i, 6))
        color_G = int(excel_all_color_sheet.cell_value(i, 7))
        color_B = int(excel_all_color_sheet.cell_value(i, 8))

        color_item = my_color(color_desc, color_class, color_l, color_a,
                              color_b, color_R, color_G, color_B)

        if color_class in all_class_color.keys():
            all_class_color[color_class].append(color_item)
        else:
            all_class_color[color_class] = [color_item]
    # for k,v in all_class_color.items():
    #   print(len(v))
    return all_class_color


def parse_color_config_table():
    global all_color_config
    global background_config
    global all_color_list
    global all_color_list_back
    global background_list

    color_lab_config_path = "./lab_color_config.xls"
    ef = xlrd.open_workbook(color_lab_config_path)
    all_color_sheet = ef.sheet_by_name("all_color")
    backgroud_sheet = ef.sheet_by_name("background")
    temp_front_color_sheet = ef.sheet_by_name("title_front_color")
    all_color_config = parse_color_table(all_color_sheet)
    background_config = parse_color_table(backgroud_sheet)
    for k, v in all_color_config.items():
        list_len = len(v)
        for item in v:
            all_color_list.append(item)
            all_color_list_back.append(item)
    for k, v in background_config.items():
        list_len = len(v)
        for item in v:
            background_list.append(item)
    return

def init():
    # 初始化模式数据
    fini_num = 0
    mode = [0, 1]
    for m in mode:
        key = "fini:num:" + str(m)
        fini_num = redis_conn.get(key)
        if fini_num == None:
            redis_conn.set(key, 0)
    return


#############page数据请求-begin#################

# 客户端请求准备页面数据
@app.route('/page_ready', methods=['GET'])
def page_ready():
    # 取用户id
    uid = request.headers.get("uid")

    # 检查当前所处的模式
    mode = 0
    key = "user:mode:" + str(uid)
    mode = redis_conn.get(key)
    if mode == None:
        expire = 60 * 60 * 2  # 2h 后过期
        mode = 0
        redis_conn.setex(key, expire, mode)
    mode = int(mode)

    # 背景颜色
    background_color = background_list[mode].rgb
    title_front_color = title_front_color_list[~mode]

    # 当前毫秒时间
    t = time.time()
    time_ms = round(t * 1000)

    # 记录用户操作
    key = "user:operator:" + str(uid)
    filed = "page_ready_" + str(mode)
    value = {}
    value["time_ms"] = time_ms
    expire = 60 * 60 * 2  # 2h 后过期
    redis_conn.hset(key, filed, json.dumps(value))
    redis_conn.expire(key, expire)
    # 回包
    proto_rs = {}
    proto_rs["code"] = 0


    rs = {}
    rs["uid"] = uid
    rs["background_color"] = color_convert.rgb_convert_hexstring(background_color)
    rs["title"] = "实验说明"
    rs["front_color"] = title_front_color
    rs["desc_text"] = "在您阅读完此说明后点击“我已准备”，首先会出现一个十字架，这是进行眼校准，您无需操作，1s后会自动出现一个带有颜色的色块即目标色块。您需记住该目标色块的颜色，5s后会出现一个不同颜色组合的4x6排列的界面，您需在该界面中找到目标色块并点击，接着会出现一个灰色界面，这是中和颜色，您也无需操作，1s后会出现一个色块，您需判断该色块与之前的目标色块是否是一个颜色，是点击“Yes”，否点击“No”。"
    rs["button_text"] = "我已准备好"

    proto_rs["data"] = [rs]
    return proto_rs

# 客户端请求校准页面数据
@app.route('/page_eye_calibration', methods=['GET'])
def page_eye_calibration():
    # 取用户id
    uid = request.headers.get("uid")

    # 检查当前所处的模式
    mode = 0
    key = "user:mode:" + str(uid)
    mode = redis_conn.get(key)
    mode = int(mode)

    # 背景颜色
    background_color = background_list[mode].rgb
    title_front_color = title_front_color_list[~mode]

    # 当前毫秒时间
    t = time.time()
    time_ms = round(t * 1000)

    # 记录用户操作
    key = "user:operator:" + str(uid)
    filed = "page_eye_calibration_" + str(mode)
    value = {}
    value["time_ms"] = time_ms
    expire = 60 * 60 * 2  # 2h 后过期
    redis_conn.hset(key, filed, json.dumps(value))
    redis_conn.expire(key, expire)

    # 回包
    proto_rs = {}
    proto_rs["code"] = 0
    rs = {}
    rs["uid"] = uid
    rs["background_color"] = color_convert.rgb_convert_hexstring(background_color)
    rs["title"] = "校准"
    rs["front_color"] = title_front_color

    proto_rs["data"] = [rs]
    return proto_rs    


# 客户端请求显示目标颜色页面数据
@app.route('/page_show_target_color', methods=['GET'])
def page_show_target_color():
    # 取用户id
    uid = request.headers.get("uid")
    
    time.sleep(4)

    # 检查当前所处的模式
    mode = 0
    key = "user:mode:" + str(uid)
    mode = redis_conn.get(key)
    mode = int(mode)

    # 根据规则取该给用户显示的颜色
    rule_target_color = 0
    rule_target_color_class = 0
    # 根据模式取当前的完成数
    fini_num = 0
    key = "fini:num:" + str(mode)
    fini_num = redis_conn.get(key)
    fini_num = int(fini_num)
    color_list_len = len(all_color_list_back)
    rand_index = int(fini_num) % color_list_len
    rule_target_color = all_color_list_back[rand_index].rgb
    rule_target_color_class = all_color_list_back[rand_index].color_class

    # 背景颜色
    background_color = background_list[mode].rgb
    title_front_color = title_front_color_list[~mode]

    # 当前毫秒时间
    t = time.time()
    time_ms = round(t * 1000)

    # 记录用户操作
    key = "user:operator:" + str(uid)
    filed = "page_show_target_color_" + str(mode)
    value = {}
    value["time_ms"] = time_ms
    value["rgb"] = rule_target_color
    value["rgb_class"] = rule_target_color_class
    expire = 60 * 60 * 2  # 2h 后过期
    redis_conn.hset(key, filed, json.dumps(value))
    redis_conn.expire(key, expire)

    # 回包
    proto_rs = {}
    proto_rs["code"] = 0
    rs = {}
    rs["uid"] = uid
    rs["background_color"] = color_convert.rgb_convert_hexstring(background_color)
    rs["title"] = "目标颜色"
    rs["front_color"] = title_front_color
    rs["target_color"] = color_convert.rgb_convert_hexstring(rule_target_color)
    rs["target_color_class"] = rule_target_color_class

    proto_rs["data"] = [rs]
    return proto_rs


# 客户端请求显示目标颜色页面数据
@app.route('/page_rand_color_set', methods=['GET'])
def page_rand_color_set():
    # 取用户id
    uid = request.headers.get("uid")

    # 检查当前所处的模式
    mode = 0
    key = "user:mode:" + str(uid)
    mode = redis_conn.get(key)
    mode = int(mode)

    # 背景颜色
    background_color = background_list[mode].rgb
    title_front_color = title_front_color_list[~mode]

    # 当前毫秒时间
    t = time.time()
    time_ms = round(t * 1000)

    # 记录用户操作
    key = "user:operator:" + str(uid)
    filed = "page_rand_color_set_" + str(mode)
    value = {}
    value["time_ms"] = time_ms
    expire = 60 * 60 * 2  # 2h 后过期
    redis_conn.hset(key, filed, json.dumps(value))
    redis_conn.expire(key, expire)

    # 读取配表中的所有颜色返回
    color_item = {}
    color_list = []
    random.shuffle(all_color_list)  # 先洗牌
    for item in all_color_list:
        color_item = {}
        color_item["rgb"] = color_convert.rgb_convert_hexstring(item.rgb)
        color_item["rgb_class"] = item.color_class
        color_list.append(color_item)

    # 回包
    proto_rs = {}
    proto_rs["code"] = 0
    rs = {}
    rs["uid"] = uid
    rs["background_color"] = color_convert.rgb_convert_hexstring(background_color)
    rs["title"] = "颜色池"
    rs["front_color"] = title_front_color
    rs["box_color_list"] = color_list
    proto_rs["data"] = [rs]
    return proto_rs


# 客户端请求显示目标颜色页面数据
@app.route('/page_test_color', methods=['GET'])
def page_test_color():
    # 取用户id
    uid = request.headers.get("uid")

    # 检查当前所处的模式
    mode = 0
    key = "user:mode:" + str(uid)
    mode = redis_conn.get(key)
    mode = int(mode)

    # 检查之前选择的颜色
    last_show_color = 0
    last_show_color_class = 0
    key = "user:operator:" + uid
    filed = "page_show_target_color_" + str(mode)
    value_json = '{}'
    value_json = redis_conn.hget(key, filed)
    z_value = json.loads(value_json)
    last_show_color = z_value["rgb"]
    last_show_color_class = int(z_value["rgb_class"])


    # 从色系中选择一个颜色
    test_class_color = 0
    class_color_list = all_color_config[last_show_color_class]
    class_color_list_len = len(class_color_list)
    test_index = random.randint(0, class_color_list_len - 1)
    test_class_color = class_color_list[test_index].rgb
    test_class_color_class = class_color_list[test_index].color_class

    # 背景颜色
    background_color = background_list[mode].rgb
    title_front_color = title_front_color_list[~mode]

    # 当前毫秒时间
    t = time.time()
    time_ms = round(t * 1000)

    # 记录用户操作
    key = "user:operator:" + str(uid)
    filed = "page_test_color_" + str(mode)
    value = {}
    value["time_ms"] = time_ms
    value["rgb"] = test_class_color
    value["rgb_class"] = test_class_color_class
    expire = 60 * 60 * 2  # 2h 后过期
    redis_conn.hset(key, filed, json.dumps(value))
    redis_conn.expire(key, expire)

    # 回包
    proto_rs = {}
    proto_rs["code"] = 0
    rs = {}
    rs["uid"] = uid
    rs["background_color"] = color_convert.rgb_convert_hexstring(background_color)
    rs["front_color"] = title_front_color
    rs["title"] = "测试"
    rs["box_color"] = color_convert.rgb_convert_hexstring(test_class_color)
    rs["box_color_class"] = test_class_color_class
    rs["yes_button_desc"] = "yes"
    rs["no_button_desc"] = "no"
    proto_rs["data"] = [rs]
    return proto_rs



# 客户端请求显示目标颜色页面数据
@app.route('/page_fini', methods=['GET'])
def page_fini():
    # 取用户id
    uid = request.headers.get("uid")
    # 检查当前所处的模式
    mode = 0
    key = "user:mode:" + str(uid)
    mode = redis_conn.get(key)
    mode = int(mode)
    # 背景颜色
    background_color = background_list[mode].rgb
    title_front_color = title_front_color_list[~mode]

    # 当前毫秒时间
    t = time.time()
    time_ms = round(t * 1000)
    # 记录用户操作
    key = "user:operator:" + str(uid)
    filed = "page_fini_" + str(mode)
    value = {}
    value["time_ms"] = time_ms
    expire = 60 * 60 * 2  # 2h 后过期
    redis_conn.hset(key, filed, json.dumps(value))
    redis_conn.expire(key, expire)

    # 记录完成次数
    key = "fini:num:" + str(mode)
    redis_conn.incr(key)

    # 填充回包
    step = 0    # 步骤
    over = 0
    timer = 2000
    desc = ""
    if 0 == mode:
        step = 1
        over = 0
        timer = 2000
        desc = "等待2s进入下一个实验"


        # 不修改模式, 保证幂等性
    if 1 == mode:
        step = 2
        over = 1
        timer = 0
        desc = "实验完成, 非常感谢您的支持, 谢谢!"
        # 这里不写完成步骤标记

    # redis写用户完成步骤标记
    key = "user:complete:" + str(uid)
    redis_conn.set(key, step)


    # 回包
    proto_rs = {}
    proto_rs["code"] = 0
    rs = {}
    rs["uid"] = uid
    rs["background_color"] = color_convert.rgb_convert_hexstring(background_color)
    rs["front_color"] = title_front_color
    rs["title"] = "总结"
    rs["over"] = over
    rs["timer"] = timer
    rs["desc"] = desc
    proto_rs["data"] = [rs]
    return proto_rs


#############page数据请求-end#################


#############模式切换请求-begin#################
#模式切换 请求, 进入下一个实验倒计时到期发送请求
@app.route('/mode_change', methods=['GET'])
def mode_change():
    # 取用户id
    uid = request.headers.get("uid")

    # 模式变更为1
    key = "user:mode:" + str(uid)
    redis_conn.set(key, 1)

    # 回包
    proto_rs = {}
    proto_rs["code"] = 0
    #
    rs = {}
    rs["uid"] = uid
    proto_rs["data"] = [rs]
    return proto_rs

# 用户登陆
@app.route('/wechat_login', methods=['POST'])
def wechat_login():
    time.sleep(1)
    index_desc = 'Welcome!'
    is_over = False
    step = 0    # 步骤

    r_json = request.get_json()
    wechat_code = r_json.get('code')
    wechat_app_id = 'wx861790198a8e0309'
    wechat_app_secret = '8bd719e12db7e700f04dceb128c39e7a'
    
    # 取用户id
    url = f'https://api.weixin.qq.com/sns/jscode2session?appid={wechat_app_id}&secret={wechat_app_secret}&js_code={wechat_code}&grant_type=authorization_code'
    res = requests.get(url)
    openid = res.json().get('openid')
    uid = openid

    # 取用户完成步骤
    key = "user:complete:" + str(uid)
    step = redis_conn.get(key)
    if step == None:
        step = 0
        redis_conn.set(key, step)
    step = int(step)

    if 0 == step:
        index_desc = "欢迎您参与我们的实验!"
    if 1 == step:
        index_desc = "欢迎, 您已完成了第一个实验, 还剩最后一个实验"
    if 2 == step:
        is_over = True
        index_desc = "您已完成我们的实验, 非常感谢您的参与, 谢谢!"

    proto_rs = {}
    proto_rs["code"] = 0
    rs = {}
    rs['msg'] = 'ok'
    rs['openid'] = openid
    rs['index_desc'] = index_desc
    rs['is_over'] = is_over
    proto_rs['data'] = rs
    return proto_rs
#############模式切换请求-end#################



#############用户操作请求-end#################

# 用户最终确认是否是目标颜色
@app.route('/op_ack_color', methods=['GET'])
def op_ack_color():
    # 取用户id， 用户操作
    uid = request.headers.get("uid")
    ack = request.headers.get("ack")

    # 检查当前所处的模式
    mode = 0
    key = "user:mode:" + str(uid)
    mode = redis_conn.get(key)
    mode = int(mode)

    # 当前毫秒时间
    t = time.time()
    time_ms = round(t * 1000)

    # 记录用户操作
    key = "user:operator:" + str(uid)
    filed = "op_ack_color_" + str(mode)
    value = {}
    value["time_ms"] = time_ms
    value["ack"] = ack
    expire = 60 * 60 * 2  # 2h 后过期
    redis_conn.hset(key, filed, json.dumps(value))
    redis_conn.expire(key, expire)

    # 回包
    proto_rs = {}
    proto_rs["code"] = 0
    #
    rs = {}
    rs["uid"] = uid
    proto_rs["data"] = [rs]
    return proto_rs

#############用户操作请求-end#################




# 解析颜色配置表
parse_color_config_table()
init()
# 启动服务
app.run()
